home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / tde10src.zip / UTILS.C < prev    next >
C/C++ Source or Header  |  1991-06-05  |  43KB  |  1,442 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - miscellaneous utilities
  10.  * Purpose: This file contains miscellaneous functions that were required
  11.  *           in more than one of the other files, or were thought to be
  12.  *           likely to be used elsewhere in the future.
  13.  * File:    utils.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  */
  18. /*********************  end of original comments   ********************/
  19.  
  20.  
  21. /*
  22.  * The utility routines have been EXTENSIVELY rewritten.  Update screens as
  23.  * needed.  Most times, only one line has changed.  Just show changed line
  24.  * in all windows if it is on screen.
  25.  *
  26.  * Support routines for text lines longer than screen width have been added.
  27.  * Currently support lines as long as 255 bytes.  If longer lines are needed,
  28.  * the assembly routines need to be modified since they use bytes (a byte
  29.  * goes from 255 to 0, unsigned).
  30.  *
  31.  * New editor name:  tde, the Thomson-Davis Editor.
  32.  * Author:           Frank Davis
  33.  * Date:             June 5, 1991
  34.  *
  35.  * This modification of Douglas Thomson's code is released into the
  36.  * public domain, Frank Davis.  You may distribute it freely.
  37.  */
  38.  
  39. #include "tdestr.h"
  40. #include "common.h"
  41. #include "define.h"
  42. #include "funcdef.h"
  43. #include "tdefunc.h"
  44. #ifdef __TURBOC__
  45.   #include <dir.h>        /* for making temporary file names etc */
  46. #endif
  47. #if defined( __MSC__ )
  48.    #include <dos.h>
  49.    #include <io.h>
  50. #endif
  51.  
  52.  
  53. /*
  54.  * Name:    myisalnum
  55.  * Purpose: To determine whether or not a character is part of a "word",
  56.  *           which in languages like Pascal means a letter, digit or
  57.  *           underscore.
  58.  * Date:    October 1, 1989
  59.  * Passed:  c: the character to be tested
  60.  * Returns: TRUE if c is an alphanumeric or '_' character, FALSE otherwise
  61.  */
  62. int  myisalnum( c )
  63. int c;
  64. {
  65. int rc;
  66.  
  67.    rc = FALSE;
  68.    if (isalnum( c ) || (c == '_'))
  69.       rc = TRUE;
  70.    return( rc );
  71. }
  72.  
  73.  
  74. /*
  75.  * Name:    check_virtual_col
  76.  * Purpose: make sure real column is displayed on screen
  77.  * Date:    June 5, 1991
  78.  * Passed:  window: current window
  79.  *          rcol: real column of cursor
  80.  *          ccol: current or logical column of cursor
  81.  */
  82. void check_virtual_col( window, rcol, ccol )
  83. windows *window;
  84. int rcol, ccol;
  85. {
  86. int bcol, ncols;
  87.  
  88.    bcol = window->bcol;
  89.    ncols = g_display.ncols - 1;
  90.  
  91.    /*
  92.     * is logical column past end of screen?
  93.     */
  94.    if (ccol > ncols) {
  95.       ccol = ccol - bcol;
  96.       if (ccol > ncols) {
  97.          ccol = ncols;
  98.          bcol = rcol - ccol;
  99.          window->dirty = LOCAL;
  100.       }
  101.  
  102.    /*
  103.     * is logical column behind start of screen?
  104.     */
  105.    } else if (ccol < 0) {
  106.       if (bcol >= -ccol)
  107.          bcol += ccol;
  108.       ccol = 0;
  109.       window->dirty = LOCAL;
  110.  
  111.    /*
  112.     * is current column < base column?
  113.     */
  114.    } else if (rcol < bcol) {
  115.       ccol = rcol;
  116.       bcol = 0;
  117.       if (ccol > ncols) {
  118.          bcol = rcol - ncols;
  119.          ccol = rcol - bcol;
  120.       }
  121.       window->dirty = LOCAL;
  122.    }
  123.  
  124.    /*
  125.     * current column + base column MUST equal real column
  126.     */
  127.    if (ccol + bcol != rcol) {
  128.       if (bcol < 0)
  129.          bcol = rcol;
  130.       ccol = rcol - bcol;
  131.       if (ccol > ncols) {
  132.          bcol = rcol - ncols;
  133.          ccol = rcol - bcol;
  134.       }
  135.       window->dirty = LOCAL;
  136.    }
  137.    window->bcol = bcol;
  138.    window->ccol = ccol;
  139.    window->rcol = rcol;
  140. }
  141.  
  142.  
  143. /*
  144.  * Name:    copy_line
  145.  * Purpose: To copy the cursor line, if necessary, into the current line
  146.  *           buffer, so that changes can be made efficiently.
  147.  * Date:    June 5, 1991
  148.  * Passed:  text_line: line to be copied to line buffer
  149.  *          line: line to display error message
  150.  * Notes:   See un_copy_line, the reverse operation.  Terminate text strings
  151.  *          with CONTROL_Z.  DO NOT use the C library string functions on
  152.  *          text in g_status.line_buff.
  153.  */
  154. void copy_line( text_line, line )
  155. text_ptr text_line;
  156. int line;
  157. {
  158. text_ptr d, s;     /* destination and source of copy */
  159. int count;         /* number of characters copied */
  160.  
  161.    /*
  162.     * copy the cursor line to the line buffer
  163.     */
  164.    d = g_status.line_buff;
  165.    s = cpf( text_line );
  166.    for (count=0; *s != CONTROL_Z; count++, s++) {
  167.       if (count >= g_display.line_length) {
  168.          *d++ = '\n';
  169.          error( WARNING, line,  "line buffer overflow - line truncated!" );
  170.          break;
  171.       }
  172.       if (*s == '\n') {
  173.          *d++ = *s;
  174.          break;
  175.       }
  176.       /*
  177.        * d is incremented after *d = *s, fyi
  178.        */
  179.       *d++ = *s;
  180.    }
  181.    *d = CONTROL_Z;
  182. }
  183.  
  184.  
  185. /*
  186.  * Name:    un_copy_line
  187.  * Purpose: To copy the cursor line, if necessary, from the current line
  188.  *           buffer, shifting the main text to make the right amount of
  189.  *           room.
  190.  * Date:    June 5, 1991
  191.  * Passed:  test_line:  pointer to location to copy line buffer
  192.  *          prompt_line:  line to display error message
  193.  * Notes:   For various reasons, trailing spaces are NOT removed when
  194.  *           returning the line buffer to the main text. Typically,
  195.  *           padding is added at the end of a line by deliberately
  196.  *           adding trailing spaces, and then uncopying the line.
  197.  *          See copy_line, the reverse operation.
  198.  */
  199. void un_copy_line( text_line, prompt_line )
  200. text_ptr text_line;
  201. int prompt_line;
  202. {
  203. text_ptr source; /* source for block move and for copying buffer line */
  204. text_ptr dest;   /* destination for block move and copy */
  205. long number;     /* length of block move */
  206. int space;
  207. int len;         /* length of current line buffer text */
  208. int curs_len;    /* length of cursor line */
  209.  
  210.    /*
  211.     * work out the lengths of the old cursor line (including the \n if any)
  212.     *  and the new current line buffer text.
  213.     */
  214.    text_line = cpf( text_line );
  215.    curs_len = linelen( text_line );
  216.    if (text_line[curs_len] == '\n')
  217.       ++curs_len;
  218.    len = find_CONTROL_Z( g_status.line_buff );
  219.    space = len - curs_len;
  220.  
  221.    /*
  222.     * if the main text buffer has run out of space, then only part of the
  223.     *  current line can be moved back into the main buffer. Warn the user
  224.     *  that some of the current line has been lost
  225.     */
  226.    if (ptoul( g_status.end_mem ) + (long)space >= ptoul( g_status.max_mem )) {
  227.       error( WARNING, prompt_line, "buffer full, part line truncated" );
  228.       len = curs_len + (int) (ptoul( g_status.max_mem ) -
  229.                               ptoul( g_status.end_mem ));
  230.    }
  231.  
  232.    /*
  233.     * move text to either make room for the extra characters in the new
  234.     *  line, or else close up the gap.
  235.     */
  236.    source = text_line + curs_len;
  237.    dest = addltop( (long)space, source );
  238.    number = ptoul( g_status.end_mem ) - ptoul( source );
  239.    hw_move( dest, source, number );
  240.    g_status.end_mem = addltop( (long)space, g_status.end_mem );
  241.  
  242.    /*
  243.     * now copy the line buffer into the space just created
  244.     */
  245.    source = g_status.line_buff;
  246.    dest = text_line;
  247.    for (; len > 0; len--)
  248.       *dest++ = *source++;
  249. }
  250.  
  251.  
  252. /*
  253.  * Name:    load_file
  254.  * Purpose: To read in a given file to the end of the main text buffer.
  255.  * Date:    June 5, 1991
  256.  * Passed:  name:   path name of file to be read
  257.  * Returns: OK if file read successfully
  258.  *          ERROR if any problem (such as out of buffer space)
  259.  * Notes:   If the file does not exist, the user is informed of an error,
  260.  *           so check first if it is OK for the file to be new.
  261.  */
  262. int  load_file( name )
  263. char *name;
  264. {
  265. int line;                       /* line on screen to display prompt */
  266. int rc;
  267.  
  268.    rc = OK;
  269.    line = g_display.nlines;
  270.  
  271.    /*
  272.     * make sure this gets set properly even if there is no file!
  273.     */
  274.    g_status.temp_end = g_status.end_mem;
  275.  
  276.    if (hw_load( name, g_status.end_mem, g_status.max_mem,
  277.            &g_status.temp_end, line ) == ERROR)
  278.       rc = ERROR;
  279.    return( rc );
  280. }
  281.  
  282. /*
  283.  * Name:    set_prompt
  284.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  285.  * Date:    October 1, 1989
  286.  * Passed:  prompt: prompt to be displayed
  287.  *          line:  line on which to display prompt
  288.  */
  289. void set_prompt( prompt, line )
  290. char *prompt;
  291. int line;
  292. {
  293.    /*
  294.     * work out where the answer should go
  295.     */
  296.    g_status.prompt_col = strlen( prompt );
  297.    g_status.prompt_line = line;
  298.  
  299.    /*
  300.     * output the prompt
  301.     */
  302.    s_output( prompt, line, 0, g_display.message_color );
  303.    eol_clear( g_status.prompt_col, line, g_display.message_color );
  304.  
  305.    /*
  306.     * ensure the cursor is in the right place
  307.     */
  308.    xygoto( g_status.prompt_col, g_status.prompt_line );
  309. }
  310.  
  311. /*
  312.  * Name:    get_name
  313.  * Purpose: To prompt the user, and read the string the user enters in
  314.  *           response.
  315.  * Date:    October 1, 1989
  316.  * Passed:  prompt: prompt to offer the user
  317.  *          lines:  no. of lines up from the bottom of the screen
  318.  *          name:   default answer
  319.  *          color:  color to display prompt
  320.  * Returns: name:   user's answer
  321.  *          OK if user entered something
  322.  *          ERROR if user aborted the command
  323.  * Notes:   Editing of the line is supported.
  324.  */
  325. int get_name( prompt, line, name, color )
  326. char *prompt;
  327. int line;
  328. char *name;
  329. int color;
  330. {
  331. int col;                /* cursor column for answer */
  332. int c;                  /* character user just typed */
  333. char *cp;               /* cursor position in answer */
  334. char *answer;           /* user's answer */
  335. int first = TRUE;       /* first character typed */
  336. int len;                /* length of answer */
  337. int plen;               /* length of prompt */
  338. int func;               /* function of key pressed */
  339. char *p;                /* for copying text in answer */
  340. char buffer[MAX_COLS+2];/* line on which name is being entered */
  341. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  342. int normal;
  343.  
  344.    /*
  345.     * set up prompt and default
  346.     */
  347.    strcpy( buffer, prompt );
  348.    plen = strlen( prompt );
  349.    answer = buffer + plen;
  350.    strcpy( answer, name );
  351.  
  352.    /*
  353.     * let user edit default into desired string
  354.     */
  355.    len = strlen( answer );
  356.    col = strlen( buffer );
  357.    cp = answer + len;
  358.    c = 0;
  359.    normal = g_display.text_color;
  360.    save_screen_line( 0, line, line_buff );
  361.    s_output( buffer, line, 0, color );
  362.    eol_clear( col, line, normal );
  363.    while (key_func[c].func != AbortCommand  &&  key_func[c].func != Rturn) {
  364.       xygoto( col, line );
  365.       c = (c=getch()) != 0 ? c : getch() | 0x100;
  366.       func = key_func[c].func;
  367.       switch (func) {
  368.          case ToggleSearchCase :
  369.             if (bm.search_case == IGNORE)
  370.                bm.search_case = MATCH;
  371.             else
  372.                bm.search_case = IGNORE;
  373.             show_search_case( );
  374.             break;
  375.          case Rturn :
  376.             answer[len] = '\0';
  377.             strcpy( name, answer );
  378.             /*
  379.              * finished
  380.              */
  381.             break;
  382.          case BackSpace :
  383.             /*
  384.              * delete to left of cursor
  385.              */
  386.             if (cp > answer) {
  387.                for (p=cp-1; p < answer+len; p++) {
  388.                   *p = *(p+1);
  389.                }
  390.                --len;
  391.                --col;
  392.                --cp;
  393.                c_output( ' ', plen+len, line, normal);
  394.                s_output( cp, line, col, color );
  395.                *(answer + len) = '\0';
  396.             }
  397.             break;
  398.          case DeleteChar :
  399.             /*
  400.              * delete char under cursor
  401.              */
  402.             if (*cp) {
  403.                for (p=cp; p < answer+len; p++) {
  404.                   *p = *(p+1);
  405.                }
  406.                --len;
  407.                c_output( ' ', plen+len, line, normal);
  408.                s_output( cp, line, col, color );
  409.                *(answer + len) = '\0';
  410.             }
  411.             break;
  412.          case DeleteLine :
  413.             /*
  414.              * delete current line
  415.              */
  416.             col = plen;
  417.             cp = answer;
  418.             *cp = '\0';
  419.             len = 0;
  420.             eol_clear( col, line, normal );
  421.             break;
  422.          case RestoreString :
  423.             /*
  424.              * restore original line
  425.              */
  426.             strcpy( answer, name );
  427.             len = strlen( answer );
  428.             col = plen + len;
  429.             cp = answer + len;
  430.             s_output( cp, line, col, color );
  431.             break;
  432.          case CharLeft :
  433.             /*
  434.              * move cursor left
  435.              */
  436.             if (cp > answer) {
  437.                col--;
  438.                cp--;
  439.             }
  440.             break;
  441.          case CharRight :
  442.             /*
  443.              * move cursor right
  444.              */
  445.             if (*cp) {
  446.                col++;
  447.                cp++;
  448.              }
  449.              break;
  450.          case BegOfLine :
  451.             /*
  452.              * move cursor to start of line
  453.              */
  454.             col = plen;
  455.             cp = answer;
  456.             break;
  457.          case EndOfLine :
  458.             /*
  459.              * move cursor to end of line
  460.              */
  461.             col = plen + len;
  462.             cp = answer + len;
  463.             break;
  464.          default :
  465.             if (c < 0x100) {
  466.                /*
  467.                 * insert character at cursor
  468.                 */
  469.                if (first) {
  470.                   /*
  471.                    * delete previous answer
  472.                    */
  473.                   col = plen;
  474.                   cp = answer;
  475.                   *cp = '\0';
  476.                   len = 0;
  477.                   eol_clear( col, line, normal );
  478.                }
  479.  
  480.                /*
  481.                 * insert new character
  482.                 */
  483.                if (col < g_display.ncols-1) {
  484.                   if (*cp == '\0') {
  485.                      ++len;
  486.                      *(answer + len) = '\0';
  487.                   }
  488.                   *cp = c;
  489.                   c_output( c, col, line, color );
  490.                   ++cp;
  491.                   ++col;
  492.                }
  493.             }
  494.             break;
  495.       }
  496.       first = FALSE;
  497.    }
  498.    restore_screen_line( 0, line, line_buff );
  499.    if (key_func[c].func == AbortCommand)
  500.       c = ERROR;
  501.    else
  502.       c = OK;
  503.    return( c );
  504. }
  505.  
  506.  
  507. /*
  508.  * Name:    get_yn
  509.  * Purpose: To input a response of yes or no.
  510.  * Date:    October 1, 1989
  511.  * Returns: the user's answer (A_??? - see tdestr.h)
  512.  */
  513. int  get_yn( )
  514. {
  515. int c;   /* the user's response */
  516. int rc;  /* return code */
  517.  
  518.    xygoto( g_status.prompt_col, g_status.prompt_line );
  519.    for (rc=-1; rc<0;) {
  520.       c = (c=getch()) != 0 ? c : getch() | 0x100;
  521.       if (key_func[c].func == AbortCommand)
  522.          rc = A_ABORT;
  523.       else {
  524.          switch ( c ) {
  525.             case 'Y':
  526.             case 'y':
  527.                rc = A_YES;
  528.                break;
  529.             case 'N':
  530.             case 'n':
  531.                rc = A_NO;
  532.                break;
  533.          }
  534.       }
  535.    }
  536.    return( rc );
  537. }
  538.  
  539.  
  540. /*
  541.  * Name:    get_oa
  542.  * Purpose: To input a response of overwrite or append.
  543.  * Date:    October 1, 1989
  544.  * Returns: the user's answer (A_??? - see tdestr.h)
  545.  */
  546. int get_oa( )
  547. {
  548. int c;   /* the user's response */
  549. int rc;  /* return code */
  550.  
  551.    rc = 0;
  552.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  553.       xygoto( g_status.prompt_col, g_status.prompt_line );
  554.       c = (c=getch()) != 0 ? c : getch() | 0x100;
  555.       c_output( c, g_display.col, g_display.line, g_display.message_color );
  556.       if (key_func[c].func == AbortCommand)
  557.          rc = A_ABORT;
  558.       switch ( c ) {
  559.          case 'O':
  560.          case 'o':
  561.             rc = A_OVERWRITE;
  562.             break;
  563.          case 'A':
  564.          case 'a':
  565.             rc = A_APPEND;
  566.             break;
  567.       }
  568.    }
  569.    return( rc );
  570. }
  571.  
  572.  
  573. /*
  574.  * Name:    display_current_window
  575.  * Purpose: display text in current window
  576.  * Date:    June 5, 1991
  577.  * Passed:  window: current window
  578.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  579.  */
  580. void display_current_window( window )
  581. windows *window;
  582. {
  583. text_ptr prev, p;      /* successive lines above the cursor */
  584. int count;          /* number of lines updated so far */
  585. int number;         /* number of lines visible in window */
  586. int attr;
  587. int i;
  588. windows w;
  589.  
  590.    /*
  591.     * work out how many lines need to be displayed
  592.     */
  593.    number = window->bottom_line - (window->top_line - 1);
  594.  
  595.    /*
  596.     * display the required number of lines, starting from the
  597.     *  cursor line
  598.     */
  599.    dup_window_info( &w, window );
  600.    w.cursor = cpb( w.cursor );
  601.    count = window->cline - window->top_line;
  602.    for (i=count; i>0; i--) {
  603.       p = find_prev( w.cursor );
  604.       if (p) {
  605.          w.cursor = p;
  606.          --w.cline;
  607.          --w.rline;
  608.       }
  609.    }
  610.    attr = g_display.text_color;
  611.    w.cursor = cpf( w.cursor );
  612.    for (i=number; i>0; i--) {
  613.       if (w.cursor) {
  614.          update_line( &w );
  615.          w.cursor = find_next( w.cursor );
  616.       } else
  617.          eol_clear( 0, w.cline, attr );
  618.       ++w.cline;
  619.       ++w.rline;
  620.    }
  621. }
  622.  
  623.  
  624. /*
  625.  * Name:    redraw_screen
  626.  * Purpose: display all visible windows if some change was GLOBAL
  627.  * Date:    June 5, 1991
  628.  * Passed:  window: current window
  629.  */
  630. void redraw_screen( window )
  631. windows *window;
  632. {
  633. windows *above;             /* window above current */
  634. windows *below;             /* window below current */
  635.  
  636.    /*
  637.     * display the current window
  638.     */
  639.    display_current_window( window );
  640.  
  641.    /*
  642.     * now update all the other windows
  643.     */
  644.    above = below = window;
  645.    while (above->prev || below->next) {
  646.       if (above->prev) {
  647.          above = above->prev;
  648.          if (window->dirty == GLOBAL && above->visible)
  649.             display_current_window( above );
  650.       }
  651.       if (below->next) {
  652.          below = below->next;
  653.          if (window->dirty == GLOBAL && below->visible)
  654.             display_current_window( below );
  655.       }
  656.    }
  657.    window->dirty = FALSE;
  658. }
  659.  
  660.  
  661. /*
  662.  * Name:    show_changed_line
  663.  * Purpose: Only one line was changed in file, just show it
  664.  * Date:    June 5, 1991
  665.  * Passed:  window: current window
  666.  */
  667. void show_changed_line( window )
  668. windows *window;
  669. {
  670. windows *above;             /* window above current */
  671. windows *below;             /* window below current */
  672. windows w;
  673. long changed_line;
  674. long top_line, bottom_line;
  675. int line_on_screen;
  676.  
  677.    if (window->dirty == LOCAL || window->dirty == GLOBAL)
  678.       update_line( window );
  679.    changed_line = window->rline;
  680.  
  681.    /*
  682.     * now update the line in all other windows
  683.     */
  684.    if (window->dirty != LOCAL) {
  685.       above = below = window;
  686.       while (above->prev || below->next) {
  687.          if (above->prev) {
  688.             above = above->prev;
  689.             dup_window_info( &w, above );
  690.          } else if (below->next) {
  691.             below = below->next;
  692.             dup_window_info( &w, below );
  693.          }
  694.          if (w.file_info == window->file_info && w.visible) {
  695.             line_on_screen = FALSE;
  696.             top_line = w.rline - (w.cline - w.top_line);
  697.             bottom_line = w.rline + (w.bottom_line - w.cline);
  698.             if (changed_line == w.rline)
  699.                line_on_screen = TRUE;
  700.             else if (changed_line < w.rline && changed_line >= top_line) {
  701.                line_on_screen = TRUE;
  702.                w.cursor = cpb( w.cursor );
  703.                while (w.rline > changed_line) {
  704.                   w.cursor = find_prev( w.cursor );
  705.                   --w.rline;
  706.                   --w.cline;
  707.                }
  708.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  709.                line_on_screen = TRUE;
  710.                w.cursor = cpf( w.cursor );
  711.                while (w.rline < changed_line) {
  712.                   w.cursor = find_next( w.cursor );
  713.                   ++w.rline;
  714.                   ++w.cline;
  715.                }
  716.             }
  717.             if (line_on_screen)
  718.                update_line( &w );
  719.          }
  720.       }
  721.    }
  722.    window->dirty = FALSE;
  723. }
  724.  
  725.  
  726. /*
  727.  * Name:    dup_window_info
  728.  * Purpose: Copy window info from one window pointer to another
  729.  * Date:    June 5, 1991
  730.  * Passed:  dw: destination window
  731.  *          sw: source window
  732.  */
  733. void dup_window_info( dw, sw )
  734. windows *dw, *sw;
  735. {
  736.    memcpy( dw, sw, sizeof( windows ) );
  737. }
  738.  
  739.  
  740. /*
  741.  * Name:    adjust_windows_cursor
  742.  * Purpose: A change has been made - window->cursors in other windows must
  743.  *          be changed to reflect adding or subing of characters.
  744.  * Date:    June 5, 1991
  745.  * Passed:  window: current window
  746.  *          net_change:  number of bytes added or subtracted from a file
  747.  *          line_change: number of lines added or subtracted from a file
  748.  * Notes:   If a file has been changed, all of the memory pointers greater
  749.  *          than window->cursor must be adjusted by the number of characters
  750.  *          added or subtracted from the file pointed to by window.
  751.  *          If a file has been truncated in one window and there is another
  752.  *          window open to the same file and its current line is near the
  753.  *          end, the current line is reset to the last line of the file.
  754.  */
  755. void adjust_windows_cursor( window, net_change, line_change )
  756. windows *window;
  757. long net_change;
  758. int  line_change;
  759. {
  760. windows *next;
  761. int reset;
  762. text_ptr p;
  763. int i;
  764. file_infos *file;
  765. file_infos *next_file;
  766.  
  767.    file = window->file_info;
  768.    next = g_status.window_list;
  769.    while (next != NULL) {
  770.       if (next != window) {
  771.          next_file = next->file_info;
  772.          if (next_file == file) {
  773.             reset = FALSE;
  774.             if (ptoul( next->cursor ) > ptoul( file->end_text ))
  775.                reset = END;
  776.             else if (ptoul( next->cursor ) < ptoul( file->start_text ))
  777.                reset = BEGIN;
  778.             else if (next->rline > window->rline) {
  779.                next->cursor = addltop( net_change, next->cursor );
  780.                if (line_change) {
  781.                   p = next->cursor;
  782.                   if (line_change < 0) {
  783.                      p = cpf( p );
  784.                      for (i=line_change; i < 0 && p != NULL; i++)
  785.                         p = find_next( p );
  786.                      if (p != NULL)
  787.                         next->cursor = p;
  788.                      else
  789.                         reset = END;
  790.                   } else if (line_change > 0) {
  791.                      p = cpb( p );
  792.                      for (i=line_change; i > 0 && p != NULL; i--)
  793.                         p = find_prev( p );
  794.                      if (p != NULL)
  795.                         next->cursor = p;
  796.                      else
  797.                         reset = BEGIN;
  798.                   }
  799.                }
  800.             }
  801.             if (reset) {
  802.                if (reset == BEGIN) {
  803.                   next->cursor = next_file->start_text;
  804.                   next->rline = 1;
  805.                   next->cline = next->top_line;
  806.                } else {
  807.                   next_file->end_text = cpb( next_file->end_text );
  808.                   p = next_file->end_text - 1;
  809.                   p = find_prev( p );
  810.                   if (p != NULL)
  811.                     next->cursor = p;
  812.                   else
  813.                      next->cursor = next_file->end_text - 1;
  814.                   next->rline  = next_file->length;
  815.                }
  816.                if (next->rline < (next->cline - (next->top_line - 1)))
  817.                   next->cline = next->rline + next->top_line - 1;
  818.                window->dirty = NOT_LOCAL;
  819.             }
  820.          } else {
  821.             if (ptoul( next_file->start_text ) > ptoul( file->start_text ))
  822.                next->cursor = addltop( net_change, next->cursor );
  823.          }
  824.       }
  825.       next = next->next;
  826.    }
  827. }
  828.  
  829.  
  830. /*
  831.  * Name:    adjust_start_end
  832.  * Purpose: a file has been modified - must restore all start and end pointers
  833.  * Date:    June 5, 1991
  834.  * Passed:  mod:  pointer to modified file structure
  835.  *          net_mod:  net modifications in the source file
  836.  * Notes:   Go through the file list and adjust the start_text and end_text
  837.  *          file pointers as needed.
  838.  */
  839. void adjust_start_end( mod_file, net_mod )
  840. file_infos *mod_file;
  841. long net_mod;
  842. {
  843. unsigned long mst, ost;
  844. file_infos *open_file;
  845.  
  846.    mst = ptoul( mod_file->start_text );
  847.    for (open_file=g_status.file_list; open_file != NULL;
  848.              open_file=open_file->next) {
  849.       ost = ptoul( open_file->start_text );
  850.       if (ost == mst)
  851.          mod_file->end_text = addltop( net_mod, mod_file->end_text );
  852.       else if (ost > mst) {
  853.          open_file->start_text = addltop( net_mod, open_file->start_text );
  854.          open_file->end_text = addltop( net_mod, open_file->end_text );
  855.       }
  856.    }
  857. }
  858.  
  859.  
  860. /*
  861.  * Name:    first_non_blank
  862.  * Purpose: To find the column in which the first non-blank character in
  863.  *           the string occurs.
  864.  * Date:    June 5, 1991
  865.  * Passed:  s:  the string to search
  866.  * Returns: the first non-blank column
  867.  */
  868. int first_non_blank( s )
  869. char *s;
  870. {
  871. int count = 0;
  872.  
  873.    s = cpf( s );
  874.    while (*s++ == ' ')
  875.       ++count;
  876.    return( count );
  877. }
  878.  
  879. /*
  880.  * Name:    page_up
  881.  * Purpose: To move the cursor one page up the window (probably more
  882.  *           intuitive to think of the text being moved down)
  883.  * Date:    June 5, 1991
  884.  * Passed:  window:   information allowing access to the current window
  885.  * Notes:   The cursor line is moved back the required number of lines
  886.  *           towards the start of the file.
  887.  *          If the start of the file is reached, then the movement stops.
  888.  */
  889. void page_up( window )
  890. windows *window;
  891. {
  892. int i;           /* count of lines scanned */
  893. text_ptr p, q;   /* previous lines */
  894.  
  895.    if (window->rline != (window->cline - (window->top_line-1))) {
  896.       q = cpb( window->cursor );
  897.       i = window->cline - (window->top_line-1);
  898.       if (( window->rline - i) < window->page) {
  899.          i = window->rline - (window->cline - (window->top_line-1));
  900.          for (; i>0; i--) {
  901.             if ((p = find_prev( q )) != NULL)
  902.                q = p;
  903.          }
  904.          window->rline = (window->cline-(window->top_line-1)) + window->page;
  905.       } else {
  906.          for (i=window->page; i>0; i--) {
  907.             if ((p = find_prev( q )) != NULL)
  908.                q = p;
  909.          }
  910.       }
  911.       window->cursor = q;
  912.       window->rline -= window->page;
  913.       window->dirty = LOCAL;
  914.    }
  915. }
  916.  
  917. /*
  918.  * Name:    page_down
  919.  * Purpose: To move the cursor one page down the window (probably more
  920.  *           intuitive to think of the text being moved up)
  921.  * Date:    June 5, 1991
  922.  * Passed:  window:   information allowing access to the current window
  923.  * Notes:   The cursor line is moved forwards the required number of lines
  924.  *           towards the end of the file.
  925.  *          If the end of the file is reached, then the movement stops.
  926.  */
  927. void page_down( window )
  928. windows *window;
  929. {
  930. int i, k;          /* count of lines scanned so far */
  931. text_ptr p, q;     /* lines below cursor */
  932.  
  933.    q = cpf( window->cursor );
  934.    k = window->cline - window->top_line;
  935.    for (i=0; i < window->page && *q != CONTROL_Z; i++, k++) {
  936.       p = find_next( q );
  937.       if (p != NULL)
  938.          q = p;
  939.       else
  940.          break;
  941.    }
  942.    if (k >= window->page) {
  943.       window->cursor = q;
  944.       window->rline += i;
  945.       window->cline = window->cline + i - window->page;
  946.       window->dirty = LOCAL;
  947.    }
  948. }
  949.  
  950. /*
  951.  * Name:    scroll_down
  952.  * Purpose: To make the necessary changes after the user has given the
  953.  *           command to scroll down the screen.
  954.  * Date:    June 5, 1991
  955.  * Passed:  window: information allowing access to the current window
  956.  * Notes:   Normally, we can just delete the top line on the window, and
  957.  *           then move the cursor up one line (so the cursor remains at
  958.  *           the same position in the file).
  959.  *          However, if the cursor was already on the top line of the
  960.  *           window, then the cursor must be moved down a line first.
  961.  */
  962. void scroll_down( window )
  963. windows *window;
  964. {
  965. text_ptr next;
  966.  
  967.    window->cursor = cpf( window->cursor );
  968.    if (window->cline == window->top_line) {
  969.       if ((next = find_next( window->cursor )) != NULL)
  970.          window->cursor = next;
  971.       else
  972.          return;
  973.       ++window->cline;
  974.       ++window->rline;
  975.    }
  976.    --window->cline;
  977.    window->dirty = LOCAL;
  978. }
  979.  
  980. /*
  981.  * Name:    scroll_up
  982.  * Purpose: To make the necessary changes after the user has given the
  983.  *           command to scroll up the screen.
  984.  * Date:    June 5, 1991
  985.  * Passed:  window: information allowing access to the current window
  986.  * Notes:   Normally, we can just insert one line at the top of the window,
  987.  *           and then move the cursor down one line (so the cursor remains at
  988.  *           the same position in the file).
  989.  *          However, if the cursor was already on the bottom line of the
  990.  *           window, then the cursor must be moved up a line first.
  991.  */
  992. void scroll_up( window )
  993. windows *window;
  994. {
  995. text_ptr prev;
  996.  
  997.    window->cursor = cpb( window->cursor );
  998.    if (window->rline != 1) {
  999.       if (window->rline == (window->cline - (window->top_line -1))) {
  1000.          if ((prev = find_prev( window->cursor )) != NULL)
  1001.             window->cursor = prev;
  1002.          --window->rline;
  1003.          --window->cline;
  1004.       } else {
  1005.          if (window->cline == window->bottom_line) {
  1006.             if ((prev = find_prev( window->cursor )) != NULL)
  1007.                window->cursor = prev;
  1008.             else
  1009.                return;
  1010.             --window->cline;
  1011.             --window->rline;
  1012.          }
  1013.          ++window->cline;
  1014.          window->dirty = LOCAL;
  1015.       }
  1016.    }
  1017. }
  1018.  
  1019. /*
  1020.  * Name:    save_file
  1021.  * Purpose: To save the current file to disk.
  1022.  * Date:    June 5, 1991
  1023.  * Passed:  window:   information allowing access to the current window
  1024.  * Notes:   If anything goes wrong, then the modified flag is set.
  1025.  *          If the file is saved successfully, then modified flag is
  1026.  *           cleared.
  1027.  */
  1028. void save_file( window )
  1029. windows *window;
  1030. {
  1031. char name[MAX_COLS]; /* name of file to be saved */
  1032. char status_line[MAX_COLS+2]; /* status line at top of window */
  1033. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1034. file_infos *file;
  1035. int rc;
  1036. int prompt_line;
  1037.  
  1038.    prompt_line = window->bottom_line;
  1039.  
  1040.    /*
  1041.     * set up file name and location of various flags
  1042.     */
  1043.    file = window->file_info;
  1044.    strcpy( name, file->file_name );
  1045.  
  1046.    /*
  1047.     * see if there was a file name - if not, then make the user
  1048.     *  supply one.
  1049.     */
  1050.    if (strlen( name ) == 0) {
  1051.       save_as_file( window );
  1052.       return;
  1053.    }
  1054.  
  1055.    /*
  1056.     * save the file
  1057.     */
  1058.    save_screen_line( 0, prompt_line, line_buff );
  1059.    combine_strings( status_line, "Saving '", name, "'" );
  1060.    s_output( status_line, prompt_line, 0, g_display.message_color );
  1061.    eol_clear( strlen( status_line ), prompt_line, g_display.message_color );
  1062.    file->end_text = cpb( file->end_text );
  1063.    if ((rc = hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
  1064.                       prompt_line )) == ERROR) {
  1065.       combine_strings( status_line, "cannot write to '", name, "'" );
  1066.       error( WARNING, prompt_line, status_line );
  1067.    }
  1068.    restore_screen_line( 0, prompt_line, line_buff );
  1069.    if (rc != ERROR) {
  1070.       file->modified = FALSE;
  1071.       file->new_file = FALSE;
  1072.    }
  1073. }
  1074.  
  1075. /*
  1076.  * Name:    save_as_file
  1077.  * Purpose: To save the current file to disk, but under a new name.
  1078.  * Date:    June 5, 1991
  1079.  * Passed:  window:   information allowing access to the current window
  1080.  */
  1081. void save_as_file( window )
  1082. windows *window;
  1083. {
  1084. char name[MAX_COLS];              /* new name for file */
  1085. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1086. char status_line[MAX_COLS+2]; /* status line at top of window */
  1087. file_infos *file;
  1088. int prompt_line;
  1089. int ok;
  1090.  
  1091.    /*
  1092.     * read in name, no default
  1093.     */
  1094.    prompt_line = window->bottom_line;
  1095.    file = window->file_info;
  1096.    save_screen_line( 0, prompt_line, line_buff );
  1097.    name[0] = '\0';
  1098.    if (get_name( "New file name: ", prompt_line, name,
  1099.                  g_display.message_color ) == OK) {
  1100.  
  1101.        /*
  1102.         * make sure it is OK to overwrite any existing file
  1103.         */
  1104.       ok = TRUE;
  1105.       if (hw_fattrib( name ) != ERROR) { /* file exists */
  1106.          set_prompt( "Overwrite existing file? (y/n): ", prompt_line );
  1107.          if (get_yn( ) != A_YES  ||  hw_unlink( name, prompt_line ) == ERROR)
  1108.             ok = FALSE;
  1109.       }
  1110.       if (ok == TRUE) {
  1111.          combine_strings( status_line, "Saving '", name, "'" );
  1112.          s_output( status_line, prompt_line, 0, g_display.message_color );
  1113.          eol_clear( strlen( status_line ), prompt_line,
  1114.                     g_display.message_color );
  1115.          file->end_text = cpb( file->end_text );
  1116.          if (hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
  1117.                       prompt_line ) == ERROR) {
  1118.             combine_strings( status_line, "cannot write to '", name, "'" );
  1119.             error( WARNING, prompt_line, status_line );
  1120.          } else
  1121.  
  1122.             /*
  1123.              * record that file is saved and not yet modified again
  1124.              */
  1125.             file->modified = FALSE;
  1126.       }
  1127.    }
  1128.    restore_screen_line( 0, prompt_line, line_buff );
  1129. }
  1130.  
  1131.  
  1132. /*
  1133.  * Name:    show_window_header
  1134.  * Purpose: To save the current file to disk, but under a new name.
  1135.  * Date:    June 5, 1991
  1136.  * Passed:  name:   name of file being edited
  1137.  *          window:   information allowing access to the current window
  1138.  * Notes:   Clear line and display file name in a lite bar
  1139.  */
  1140. void show_window_header( name, window )
  1141. char *name;
  1142. windows *window;
  1143. {
  1144. char status_line[MAX_COLS+2]; /* status line at top of window */
  1145. char *p, *q;            /* for setting up status line */
  1146.  
  1147.    memset( status_line, ' ', MAX_COLS );
  1148.    status_line[MAX_COLS] = '\0';
  1149.    q = name;
  1150.    p = status_line + 2;
  1151.    while (*q)
  1152.       *p++ = *q++;
  1153.    s_output( status_line, window->top_line-1, 0, g_display.head_color );
  1154. }
  1155.  
  1156.  
  1157. /*
  1158.  * Name:    show_size_name
  1159.  * Purpose: show 'size' line lite bar header
  1160.  * Date:    June 5, 1991
  1161.  * Passed:  window:   information allowing access to the current window
  1162.  */
  1163. void show_size_name( window )
  1164. windows *window;
  1165. {
  1166. char size_line[MAX_COLS+2]; /* status line at top of window */
  1167.  
  1168.    strcpy( size_line, " size = " );
  1169.    s_output( size_line, window->top_line-1, 49, g_display.head_color );
  1170. }
  1171.  
  1172.  
  1173. /*
  1174.  * Name:    show_size
  1175.  * Purpose: show number of lines in file
  1176.  * Date:    June 5, 1991
  1177.  * Passed:  window:   information allowing access to the current window
  1178.  */
  1179. void show_size( window )
  1180. windows *window;
  1181. {
  1182. char size_line[MAX_COLS+2]; /* status line at top of window */
  1183. char csize[20];
  1184. char *p, *q;            /* for setting up status line */
  1185.  
  1186.    strcpy( size_line, "        " );
  1187.    p = size_line;
  1188.    ltoa( window->file_info->length, csize, 10 );
  1189.    q = csize;
  1190.    while (*q)
  1191.       *p++ = *q++;
  1192.    *p++ = ' ';
  1193.    *p = '\0';
  1194.    s_output( size_line, window->top_line-1, 57, g_display.head_color );
  1195. }
  1196.  
  1197.  
  1198. /*
  1199.  * Name:    quit
  1200.  * Purpose: To close the current window without saving the current file.
  1201.  * Date:    June 5, 1991
  1202.  * Passed:  window: information allowing access to the current window
  1203.  * Notes:   If the file has been modified but not saved, then the user is
  1204.  *           given a second chance before the changes are discarded.
  1205.  *          Note that this is only necessary if this is the last window
  1206.  *           that refers to the file. If another window still refers to
  1207.  *           the file, then the check can be left until later.
  1208.  */
  1209. void quit( window, stop )
  1210. windows *window;
  1211. int *stop;
  1212. {
  1213. int prompt_line;
  1214. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1215. file_infos *file;
  1216. windows *wp;
  1217. int count = 0;
  1218.  
  1219.    prompt_line = window->bottom_line;
  1220.    file = window->file_info;
  1221.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1222.       if (wp->file_info == file && wp->visible)
  1223.          ++count;
  1224.    }
  1225.    if (file->modified && count == 1) {
  1226.       save_screen_line( 0, prompt_line, line_buff );
  1227.       set_prompt( "Abandon changes? (y/n): ", prompt_line );
  1228.       if (get_yn( ) != A_YES) {
  1229.          restore_screen_line( 0, prompt_line, line_buff );
  1230.          return;
  1231.       }
  1232.    }
  1233.  
  1234.    /*
  1235.     * remove window, allocate screen lines to other windows etc
  1236.     */
  1237.    finish( window, stop );
  1238. }
  1239.  
  1240.  
  1241. /*
  1242.  * Name:    move_up
  1243.  * Purpose: To move the cursor one line up the screen.
  1244.  * Date:    June 5, 1991
  1245.  * Passed:  window:   information allowing access to the current window
  1246.  * Notes:   If the cursor is at the top of the window, then the file must
  1247.  *           be scrolled down.
  1248.  *          If the cursor is already on the first line of the file, then
  1249.  *           this command can be ignored.
  1250.  */
  1251. void move_up( window )
  1252. windows *window;
  1253. {
  1254. text_ptr p;   /* the previous line on the screen */
  1255.  
  1256.    /*
  1257.     * if no previous line, give up
  1258.     */
  1259.    window->cursor = cpb( window->cursor );
  1260.    if ((p = find_prev( window->cursor )) != NULL) {
  1261.       window->cursor = p;
  1262.       --window->rline;           /* ALWAYS decrement line counter */
  1263.       if (window->cline == window->top_line) {
  1264.          window_scroll_down( window->top_line, window->bottom_line );
  1265.          update_line( window );
  1266.       } else
  1267.          --window->cline;    /* we aren't at top of screen - so move up */
  1268.    }
  1269. }
  1270.  
  1271.  
  1272. /*
  1273.  * Name:    move_down
  1274.  * Purpose: To move the cursor one line down the screen.
  1275.  * Date:    June 5, 1991
  1276.  * Passed:  window:   information allowing access to the current window
  1277.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1278.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1279.  *           then scroll up until cursor is at top of screen.
  1280.  */
  1281. void move_down( window )
  1282. windows *window;
  1283. {
  1284. text_ptr p;
  1285. int bottom_line;
  1286.  
  1287.    bottom_line = window->bottom_line;
  1288.    window->cursor = cpf( window->cursor );
  1289.    if ((p = find_next( window->cursor )) != NULL) {
  1290.       window->cursor = p;
  1291.       ++window->rline;                /* ALWAYS increment line counter */
  1292.       if (window->cline == bottom_line) {
  1293.          window_scroll_up( window->top_line, bottom_line );
  1294.          update_line( window );
  1295.       } else
  1296.          ++window->cline;     /* if not at bottom of screen move down */
  1297.    } else if (window->cline > window->top_line) {
  1298.       --window->cline;
  1299.       window_scroll_up( window->top_line, bottom_line );
  1300.    }
  1301. }
  1302.  
  1303.  
  1304. /*
  1305.  * Name:    move_left
  1306.  * Purpose: To move the cursor one character to the left
  1307.  * Date:    June 5, 1991
  1308.  * Passed:  window:   information allowing access to the current window
  1309.  * Notes:   If the cursor is already at the left of the screen, then
  1310.  *           scroll horizontally if we're not at beginning of line.
  1311.  */
  1312. void move_left( window )
  1313. windows *window;
  1314. {
  1315.    if (window->ccol > 0) {
  1316.       --window->ccol;
  1317.       --window->rcol;
  1318.    } else if (window->ccol == 0 && window->rcol > 0) {
  1319.       --window->rcol;
  1320.       --window->bcol;
  1321.       window->dirty = LOCAL;
  1322.    }
  1323. }
  1324.  
  1325.  
  1326. /*
  1327.  * Name:    move_right
  1328.  * Purpose: To move the cursor one character to the right
  1329.  * Date:    June 5, 1991
  1330.  * Passed:  window:   information allowing access to the current window
  1331.  * Notes:   If the cursor is already at the right of the screen (logical
  1332.  *          column 80) then scroll horizontally right.
  1333.  */
  1334. void move_right( window )
  1335. windows *window;
  1336. {
  1337. int max_col;
  1338.  
  1339.    max_col = g_display.ncols - 1;
  1340.    if (window->ccol < max_col) {
  1341.       ++window->ccol;
  1342.       ++window->rcol;
  1343.    } else if (window->ccol == max_col && window->rcol < g_display.line_length) {
  1344.       ++window->rcol;
  1345.       ++window->bcol;
  1346.       window->dirty = LOCAL;
  1347.    }
  1348. }
  1349.  
  1350.  
  1351. /*
  1352.  * Name:    word_left
  1353.  * Purpose: To move the cursor one word to the left.
  1354.  * Date:    June 5, 1991
  1355.  * Passed:  window:   information allowing access to the current window
  1356.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1357.  *          which must be separated by other characters.
  1358.  */
  1359. void word_left( window )
  1360. windows *window;
  1361. {
  1362. text_ptr p;   /* text pointer */
  1363. int len;      /* length of current line */
  1364. int c;        /* character at pointer */
  1365. int check = 0;
  1366.  
  1367.    p = cpb( window->cursor );
  1368.    len = linelen( p );
  1369.    if (window->rcol > len)
  1370.      p += len;
  1371.    else
  1372.      p += window->rcol;
  1373.  
  1374.    for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
  1375.       c = *--p;
  1376.       if (check > 8000) {
  1377.          p = cpb( p );
  1378.          check = 0;
  1379.       }
  1380.    }
  1381.    if (c == CONTROL_Z)
  1382.       return;
  1383.    for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1384.       c = *--p;
  1385.       if (check > 8000) {
  1386.          p = cpb( p );
  1387.          check = 0;
  1388.       }
  1389.    }
  1390.    if (c == CONTROL_Z)
  1391.       return;
  1392.    for (;c != CONTROL_Z && myisalnum( c ); check++) {
  1393.       c = *--p;
  1394.       if (check > 8000) {
  1395.          p = cpb( p );
  1396.          check = 0;
  1397.       }
  1398.    }
  1399.    find_adjust( window, ++p );
  1400. }
  1401.  
  1402.  
  1403. /*
  1404.  * Name:    word_right
  1405.  * Purpose: To move the cursor one word to the right.
  1406.  * Date:    June 5, 1991
  1407.  * Passed:  window:   information allowing access to the current window
  1408.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1409.  *           which must be separated by other characters.
  1410.  */
  1411. void word_right( window )
  1412. windows *window;
  1413. {
  1414. int len;     /* length of current line */
  1415. text_ptr p;  /* text pointer */
  1416. int c;       /* character at pointer */
  1417. int check;
  1418.  
  1419.    p = cpb( window->cursor );
  1420.    len = linelen( p );
  1421.    if (window->rcol > len)
  1422.      p += len;
  1423.    else
  1424.      p += window->rcol;
  1425.    for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
  1426.       c = *++p;
  1427.       if (check > 8000) {
  1428.          p = cpf( p );
  1429.          check = 0;
  1430.       }
  1431.    }
  1432.    for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1433.       c = *++p;
  1434.       if (check > 8000) {
  1435.          p = cpf( p );
  1436.          check = 0;
  1437.       }
  1438.    }
  1439.    if (c != CONTROL_Z)
  1440.       find_adjust( window, p );
  1441. }
  1442.